﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Hosting;
using System.Web.Optimization;
using Mvc4Demo.Extensions;
using Newtonsoft.Json;

namespace Mvc4Demo.Core
{
    //http://stackoverflow.com/questions/18577061/asp-net-mvc-web-api-custom-dynamic-bundle-working-in-production-but-not-dev
    public class CustomBundle : Bundle
    {
        private readonly List<Type> _registerdTypes = new List<Type>();

        public CustomBundle(string virtualPath)
            :base(virtualPath,  new CustomBundleTransform())
        {
        }

        public IEnumerable<Type> RegisterdTypes
        {
            get { return _registerdTypes; }
        }

        public virtual CustomBundle Include(Type type)
        {
            _registerdTypes.Add(type);
            return this;
            //return Include(string.Format("~/{0}", type.Name)) as CustomBundle;
        }
        public override BundleResponse GenerateBundleResponse(BundleContext context)
        {
            return base.GenerateBundleResponse(context);
        }

        public override BundleResponse ApplyTransforms(BundleContext context, string bundleContent, IEnumerable<BundleFile> bundleFiles)
        {
            return base.ApplyTransforms(context, bundleContent, bundleFiles);
        }
    }

    public class CustomBundleTransform : IBundleTransform
    {
        public void Process(BundleContext context, BundleResponse response)
        {
            var bundle = context.BundleCollection.FirstOrDefault(b => b.Path == context.BundleVirtualPath) as CustomBundle;

            if (bundle == null)
                return;
            var directoryPath = HttpContext.Current.Server.MapPath(bundle.Path);

            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            var files = new List<BundleFile>();

            foreach (var registerdType in bundle.RegisterdTypes)
            {
                var fileName = string.Format("{0}/{1}.js", bundle.Path, registerdType.Name);
                files.Add(new BundleFile(bundle.Path, new CustomVirtualFile(fileName)));
                var tempObject = Activator.CreateInstance(registerdType);
                KnockoutControlExtensions.BuildViewModel(tempObject, registerdType.Name);
            }

            response.Files = files;

            var script = new StringBuilder("<script type=\"text/javascript\">");

            foreach (var builder in KnockoutControlExtensions.KnockoutViewModelDictionary)
            {
                var fileName = string.Format("{0}/{1}.js", directoryPath, builder.Key);
                
                File.WriteAllText(fileName, builder.Value.ToString());
                script.Append("\n");
                script.Append(builder.Value);
            }

            //var files = bundle
            //    .RegisterdTypes
            //    .Select(rt =>
            //            new BundleFile(bundle.Path, new CustomVirtualFile(rt.Name)))
            //    .ToList();
            //response.Files = new List<BundleFile>
            //    {
            //        new BundleFile(bundle.Path, new CustomVirtualFile(bundle.Path))
            //    };

            script.Append("</script>");

            response.Content = script.ToString(); //string.Format(";var obj = {0};", JsonConvert.SerializeObject(bundle.KeyValues));
            response.ContentType = "application/javascript";
            response.Cacheability = HttpCacheability.Server;
            context.UseServerCache = false;

            context.EnableOptimizations = true;
        }
    }

    public class CustomVirtualFile : VirtualFile
    {
        public CustomVirtualFile(string virtualPath) : base(virtualPath)
        {
        }

        public override bool IsDirectory
        {
            get { return false; }
        }

        public override Stream Open()
        {
            throw new NotImplementedException();
        }
    }
}